/**
 * eknows base components
 *
 * Copyright Leon
 * Date 2017-08-30
 */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {
		//AMD模块调用方式
		define( [ "jquery" ], factory );
	} else {
		//浏览器直接调用
		factory( jQuery );
	}
}(function( $ ) {
	
var component_uuid = 0,
	component_slice = Array.prototype.slice;

//UI状态
var EKNOWSUI_STATE_DISABLED = "eknowsui-state-disabled",
	EKNOWSUI_STATE_HOVER = "eknowsui-state-hover",
	EKNOWSUI_STATE_FOCUS = "eknowsui-state-focus";

//组件基类构造函数
$.component = function(name, base, prototype) {
	var fullName,	//组件全名 
		existingConstructor, //已经存在的构造器，组件已经定义过至少一次 
		constructor,	//当前定义的构造器 
		basePrototype,	//基本原型对象
		proxiedPrototype = {},	//代理原型对象，拷贝自prototype参数
		namespace = name.split(".")[0];	//组件名称空间
	
	//设置组件名称
	name = name.split(".")[1];
	fullName = namespace + "-" + name;
	
	//可以不传入base参数，则默认继承基类$.Component
	if (!prototype) {
		prototype = base;
		base = $.Component;
	}
	
	//构建伪类选择器
	$.expr[":"][fullName.toLowerCase] = function() {
		return !!$.data( elem, fullName );
	};
	
	//创建构造器
	$[namespace] = $[namespace] || {};
	existingConstructor = $[namespace][name];
	constructor = $[namespace][name] = function(options, element) {
		if (!this._createComponent) {
			return new constructor( options, element );
		}
		
		if ( arguments.length ) {
			this._createComponent( options, element );
		}
	};
	
	$.extend( constructor, existingConstructor, {
		version: prototype.version,
		//组件重定义时用到
		_proto: $.extend( {}, prototype ),
		//子构造器，重定义时用到
		_childConstructors: []
	});
	
	//创建基础原型对象，该对象将作为所有组件的原型对象
	basePrototype = new base();
	basePrototype.options = $.component.extend( {}, basePrototype.options );
	
	//设置构造函数的原型对象
	$.each( prototype, function( prop, value ) {
		if ( !$.isFunction( value ) ) {
			proxiedPrototype[ prop ] = value;
			return;
		}
		proxiedPrototype[ prop ] = (function() {
			var _super = function() {
					return base.prototype[ prop ].apply( this, arguments );
				},
				_superApply = function( args ) {
					return base.prototype[ prop ].apply( this, args );
				};
			return function() {
				var __super = this._super,
					__superApply = this._superApply,
					returnValue;

				this._super = _super;
				this._superApply = _superApply;

				returnValue = value.apply( this, arguments );

				this._super = __super;
				this._superApply = __superApply;

				return returnValue;
			};
		})();
	});
	constructor.prototype = $.component.extend( basePrototype, {
		componentEventPrefix: existingConstructor ? (basePrototype.componentEventPrefix || name) : name
	}, proxiedPrototype, {
		constructor: constructor,
		namespace: namespace,
		componentName: name,
		componentFullName: fullName
	});
	
	//组件重定义时，更改继承结构
	if ( existingConstructor ) {
		$.each( existingConstructor._childConstructors, function( i, child ) {
			var childPrototype = child.prototype;

			$.component( childPrototype.namespace + "." + childPrototype.componentName, constructor, child._proto );
		});
		delete existingConstructor._childConstructors;
	} else {
		base._childConstructors.push( constructor );
	}

	$.component.bridge( name, constructor );

	return constructor;
};

//自定义继承函数
$.component.extend = function( target ) {
	var input = component_slice.call( arguments, 1 ),
		inputIndex = 0,
		inputLength = input.length,
		key,
		value;
	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {

				if ( $.isPlainObject( value ) ) {
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.component.extend( {}, target[ key ], value ) :
						$.component.extend( {}, value );
				} else {
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

//连接对象，构造器，方法的调用过程
$.component.bridge = function( name, object ) {
	var fullName = object.prototype.componentFullName || name;
	$.fn[ name ] = function( options ) {
		var isMethodCall = typeof options === "string",
			args = component_slice.call( arguments, 1 ),
			returnValue = this;

		if ( isMethodCall ) {
			this.each(function() {
				var methodValue,
					instance = $.data( this, fullName );
				if ( options === "instance" ) {
					returnValue = instance;
					return false;
				}
				if ( !instance ) {
					return $.error( "cannot call methods on " + name + " prior to initialization; " +
						"attempted to call method '" + options + "'" );
				}
				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
					return $.error( "no such method '" + options + "' for " + name + " component instance" );
				}
				methodValue = instance[ options ].apply( instance, args );
				if ( methodValue !== instance && methodValue !== undefined ) {
					returnValue = methodValue && methodValue.jquery ?
						returnValue.pushStack( methodValue.get() ) :
						methodValue;
					return false;
				}
			});
		} else {
			if ( args.length ) {
				options = $.component.extend.apply( null, [ options ].concat(args) );
			}

			this.each(function() {
				var instance = $.data( this, fullName );
				if ( instance ) {
					instance.option( options || {} );
					if ( instance._init ) {
						instance._init();
					}
				} else {
					$.data( this, fullName, new object( options, this ) );
				}
			});
		}

		return returnValue;
	};
};

$.Component = function() {};
$.Component._childConstructors = [];

$.Component.prototype = {
	componentName: "component",
	componentEventPrefix: "",
	defaultElement: "<div>",
	options: {
		disabled: false,

		//bootstrap图标class标签
		baseIconClass: "eknowsicon",
		
		//创建回调方法
		create: null
	},
	//子类初始化时调用
	_createComponent: function( options, element ) {
		element = $( element || this.defaultElement || this )[ 0 ];
		this.element = $( element );
		this.uuid = component_uuid++;
		this.eventNamespace = "." + this.componentName + this.uuid;

		this.bindings = $();
		this.hoverable = $();
		this.focusable = $();

		if ( element !== this ) {
			$.data( element, this.componentFullName, this );
			this._on( true, this.element, {
				remove: function( event ) {
					if ( event.target === element ) {
						this.destroy();
					}
				}
			});
			this.document = $( element.style ?
				//document元素
				element.ownerDocument :
				//window或document元素
				element.document || element );
			this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
		}

		this.options = $.component.extend( {},
			this.options,
			this._getCreateOptions(),
			options );

		this._create();
		this._trigger( "create", null, this._getCreateEventData() );
		this._init();
	},
	
	//设置为空函数
	_getCreateOptions: $.noop,
	_getCreateEventData: $.noop,
	_create: $.noop,
	_init: $.noop,

	destroy: function() {
		this._destroy();
		//移除事件监听器
		//事件绑定必须通过this._on
		this.element
			.unbind( this.eventNamespace )
			.removeData( this.componentFullName )
			.removeData( $.camelCase( this.componentFullName ) );
		this.component()
			.unbind( this.eventNamespace )
			.removeAttr( "aria-disabled" )
			.removeClass(
				this.componentFullName + "-disabled " +
				EKNOWSUI_STATE_DISABLED );

		//清空事件和状态
		this.bindings.unbind( this.eventNamespace );
		this.hoverable.removeClass( EKNOWSUI_STATE_HOVER );
		this.focusable.removeClass( EKNOWSUI_STATE_FOCUS );
	},
	
	_destroy: $.noop,

	//返回组件的元素
	component: function() {
		return this.element;
	},

	//设置或获取配置选项
	option: function( key, value ) {
		var options = key,
			parts,
			curOption,
			i;

		if ( arguments.length === 0 ) {
			//返回全部option时保证拷贝一份新的对象
			return $.component.extend( {}, this.options );
		}

		if ( typeof key === "string" ) {
			//支持a.b与{a:{b:?}}风格的属性设置
			options = {};
			parts = key.split( "." );
			key = parts.shift();
			if ( parts.length ) {
				curOption = options[ key ] = $.component.extend( {}, this.options[ key ] );
				for ( i = 0; i < parts.length - 1; i++ ) {
					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
					curOption = curOption[ parts[ i ] ];
				}
				key = parts.pop();
				if ( arguments.length === 1 ) {
					return curOption[ key ] === undefined ? null : curOption[ key ];
				}
				curOption[ key ] = value;
			} else {
				//获取key属性值
				if ( arguments.length === 1 ) {
					return this.options[ key ] === undefined ? null : this.options[ key ];
				}
				options[ key ] = value;
			}
		}

		this._setOptions( options );

		return this;
	},
	
	//设置选项，传入整个对象
	_setOptions: function( options ) {
		var key;

		for ( key in options ) {
			this._setOption( key, options[ key ] );
		}

		return this;
	},
	
	//设置选项，传入键值对
	_setOption: function( key, value ) {
		this.options[ key ] = value;

		//如果是设置disabled状态，立即触发
		if ( key === "disabled" ) {
			this.component()
				.toggleClass( this.componentFullName + "-disabled", !!value );

			if ( value ) {
				this.hoverable.removeClass( EKNOWSUI_STATE_HOVER );
				this.focusable.removeClass( EKNOWSUI_STATE_FOCUS );
			}
		}

		return this;
	},

	//启用元素
	enable: function() {
		return this._setOptions({ disabled: false });
	},
	
	//禁用元素
	disable: function() {
		return this._setOptions({ disabled: true });
	},

	//注册事件监听器
	_on: function( suppressDisabledCheck, element, handlers ) {
		var delegateElement,
			instance = this;

		//参数缺失处理
		if ( typeof suppressDisabledCheck !== "boolean" ) {
			handlers = element;
			element = suppressDisabledCheck;
			suppressDisabledCheck = false;
		}

		if ( !handlers ) {
			handlers = element;
			element = this.element;
			delegateElement = this.component();
		} else {
			element = delegateElement = $( element );
			this.bindings = this.bindings.add( element );
		}
		
		//事件代理，允许进行disable检测
		$.each( handlers, function( event, handler ) {
			function handlerProxy() {

				//开启disabled检测，如果disabled成立，不注册事件监听器
				if ( !suppressDisabledCheck &&
						( instance.options.disabled === true ||
							$( this ).hasClass( EKNOWSUI_STATE_DISABLED ) ) ) {
					return;
				}
				
				//代理将事件对象替换成ui对象
				return ( typeof handler === "string" ? instance[ handler ] : handler )
					.apply( instance, arguments );
			}

			if ( typeof handler !== "string" ) {
				handlerProxy.guid = handler.guid =
					handler.guid || handlerProxy.guid || $.guid++;
			}

			var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
				eventName = match[1] + instance.eventNamespace,
				selector = match[2];
			if ( selector ) {
				delegateElement.delegate( selector, eventName, handlerProxy );
			} else {
				element.bind( eventName, handlerProxy );
			}
		});
	},

	//移除事件监听器
	_off: function( element, eventName ) {
		eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
			this.eventNamespace;
		element.unbind( eventName ).undelegate( eventName );

		//避免内存泄漏
		this.bindings = $( this.bindings.not( element ).get() );
		this.focusable = $( this.focusable.not( element ).get() );
		this.hoverable = $( this.hoverable.not( element ).get() );
	},

	//延迟处理事件
	_delay: function( handler, delay ) {
		function handlerProxy() {
			return ( typeof handler === "string" ? instance[ handler ] : handler )
				.apply( instance, arguments );
		}
		var instance = this;
		return setTimeout( handlerProxy, delay || 0 );
	},

	//添加元素的鼠标悬停状态
	_hoverable: function( element ) {
		this.hoverable = this.hoverable.add( element );
		this._on( element, {
			mouseenter: function( event ) {
				$( event.currentTarget ).addClass( EKNOWSUI_STATE_HOVER );
			},
			mouseleave: function( event ) {
				$( event.currentTarget ).removeClass( EKNOWSUI_STATE_HOVER );
			}
		});
	},

	//添加元素的焦点获取状态
	_focusable: function( element ) {
		this.focusable = this.focusable.add( element );
		this._on( element, {
			focusin: function( event ) {
				$( event.currentTarget ).addClass( EKNOWSUI_STATE_FOCUS );
			},
			focusout: function( event ) {
				$( event.currentTarget ).removeClass( EKNOWSUI_STATE_FOCUS );
			}
		});
	},

	//触发指定类型的事件
	_trigger: function( type, event, data ) {
		var prop, orig,
			callback = this.options[ type ];

		data = data || {};
		event = $.Event( event );
		event.type = ( type === this.componentEventPrefix ?
			type :
			this.componentEventPrefix + type ).toLowerCase();
		//替换事件的触发对象为调用trigger方法的元素
		event.target = this.element[ 0 ];

		//拷贝原始事件的对象属性
		orig = event.originalEvent;
		if ( orig ) {
			for ( prop in orig ) {
				if ( !( prop in event ) ) {
					event[ prop ] = orig[ prop ];
				}
			}
		}

		this.element.trigger( event, data );
		return !( $.isFunction( callback ) &&
			callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
			event.isDefaultPrevented() );
	}	
};

//添加元素显示或隐藏方法
$.each( {show: "fadeIn", hide: "fadeOut"}, function( method, defaultEffect ) {
	$.Component.prototype[ "_" + method ] = function( element, options, callback ) {
		if ( typeof options === "string" ) {
			options = { effect: options };
		}
		var hasOptions,
			effectName = !options ?
				method :
				options === true || typeof options === "number" ?
					defaultEffect :
					options.effect || defaultEffect;
		options = options || {};
		if ( typeof options === "number" ) {
			options = { duration: options };
		}
		hasOptions = !$.isEmptyObject( options );
		options.complete = callback;
		if ( options.delay ) {
			element.delay( options.delay );
		}
		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
			element[ method ]( options );
		} else if ( effectName !== method && element[ effectName ] ) {
			element[ effectName ]( options.duration, options.easing, callback );
		} else {
			element.queue(function( next ) {
				$( this )[ method ]();
				if ( callback ) {
					callback.call( element[ 0 ] );
				}
				next();
			});
		}
	};
});
	
}));